/**CircuitBreakerConfigurationProperties：
 *      private Duration waitDurationInOpenState;
 *      private Duration slowCallDurationThreshold;
 *      private Duration maxWaitDurationInHalfOpenState;
 *      private Float failureRateThreshold;
 *      private Float slowCallRateThreshold;
 *      private SlidingWindowType slidingWindowType;
 *      private Integer slidingWindowSize;
 *      private Integer minimumNumberOfCalls;
 *      private Integer permittedNumberOfCallsInHalfOpenState;
 *      private Boolean automaticTransitionFromOpenToHalfOpenEnabled;
 *      private Boolean writableStackTraceEnabled;
 *      private Boolean allowHealthIndicatorToFail;
 *      private Integer eventConsumerBufferSize;
 *      private Boolean registerHealthIndicator;
 *      private Class<Predicate<Throwable>> recordFailurePredicate;
 *      private Class<? extends Throwable>[] recordExceptions;
 *      private Class<? extends Throwable>[] ignoreExceptions;
 *      private String baseConfig;
 *      private Boolean enableExponentialBackoff;
 *      private Double exponentialBackoffMultiplier;
 *      private Duration exponentialMaxWaitDurationInOpenState;
 *      private Boolean enableRandomizedWait;
 *      private Double randomizedWaitFactor;
 *RetryConfigurationProperties：
 *      private Duration waitDuration;
 *      private Integer maxRetryAttempts;
 *      private Class<? extends Predicate<Throwable>> retryExceptionPredicate;
 *      private Class<? extends Predicate<Object>> resultPredicate;
 *      private Class<? extends Throwable>[] retryExceptions;
 *      private Class<? extends Throwable>[] ignoreExceptions;
 *      private Integer eventConsumerBufferSize;
 *      private Boolean enableExponentialBackoff;
 *      private Double exponentialBackoffMultiplier;
 *      private Boolean enableRandomizedWait;
 *      private Double randomizedWaitFactor;
 *      private String baseConfig;
 * RateLimiterConfigurationProperties
 *      private Integer limitForPeriod;
 *      private Duration limitRefreshPeriod;
 *      private Duration timeoutDuration;
 *      private Boolean subscribeForEvents;
 *      private Boolean allowHealthIndicatorToFail;
 *      private Boolean registerHealthIndicator;
 *      private Integer eventConsumerBufferSize;
 *      private Boolean writableStackTraceEnabled;
 *      private String baseConfig;
 */
package com.example.demoresilience4jconsumer;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.retry.annotation.Retry;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
;
import java.util.HashMap;
import java.util.Map;

@RestController
public class MyWebClient {
    @Autowired
    DiscoveryClient discoveryClient;

    //启用负载均衡
    @Autowired
    LoadBalancerClient loadBalancerClient;

    @Autowired
    RestTemplate restTemplate;

    //从Eureka中根据服务名称选择第一一个可用服务
    @RequestMapping(value="/ulogin1",produces = "application/json;charset=UTF-8")
    @CircuitBreaker(name = "cbA", fallbackMethod = "myFallBackRestTemplate")
    @Retry(name = "retryA")
    @RateLimiter(name = "rltA")
    public Map userlogin1() {
//        List<ServiceInstance> list = discoveryClient.getInstances ("userlogin");
//        ServiceInstance serviceInstance=list.get(0);

        //启用负载均衡
        ServiceInstance serviceInstance=loadBalancerClient.choose("USERLOGIN");

        String serviceUrl = serviceInstance.getUri().toString();
        System.out.println(serviceUrl);
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.getForObject(serviceUrl + "/login", Map.class);
    }

    @RequestMapping(value="/ulogin2",produces = "application/json;charset=UTF-8")
    @CircuitBreaker(name = "cbA", fallbackMethod = "myFallBackRestTemplate")
    public Map userlogin2() {
        return restTemplate.getForObject("http://USERLOGIN/login", Map.class);
    }


    public Map myFallBackRestTemplate(Throwable throwable) {
        HashMap<String, String> map = new HashMap<>();
        map.put("error Resilience4j RestTemplate call:", "服务器繁忙");
        return map;
    }


    @Autowired
    private WebClient webClient;

    @RequestMapping(value="/ulogin3",produces = "application/json;charset=UTF-8")
    @CircuitBreaker(name = "cbA", fallbackMethod = "myFallBackWebClient")
    public Mono<Map> userlogin3() {
        String url = "http://USERLOGIN/login";
        Mono<Map> result = webClient.get().uri(url)
                .retrieve().bodyToMono(Map.class);
        return result;
    }

    public Mono<Map> myFallBackWebClient(Throwable throwable) {
        Mono<Map> mmap = Mono.fromCallable(() -> {
            Map<String, String> map = new HashMap<>();
            map.put("error Resilience4j WebClient call:", "服务器繁忙");
            return map;
        });
        return mmap;
    }
}

